/**
 * 自动查询构建器工具函数
 * 提供简洁的条件构建工具
 * @author sun
 * @date 2024-03-30
 */

import { QueryOperator } from './types';

/**
 * 查询工具类
 * 提供静态方法用于快速构建查询条件
 */
export const QueryTools = {
  /**
   * 构建等于条件
   * @param field 字段名
   * @param value 条件值
   */
  equal: (field: string, value: any): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.EQUAL, field, value];
  },

  /**
   * 构建不等于条件
   * @param field 字段名
   * @param value 条件值
   */
  notEqual: (field: string, value: any): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.NOT_EQUAL, field, value];
  },

  /**
   * 构建大于条件
   * @param field 字段名
   * @param value 条件值
   */
  greaterThan: (field: string, value: any): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.GREATER_THAN, field, value];
  },

  /**
   * 构建大于等于条件
   * @param field 字段名
   * @param value 条件值
   */
  greaterThanOrEqual: (field: string, value: any): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.GREATER_THAN_OR_EQUAL, field, value];
  },

  /**
   * 构建小于条件
   * @param field 字段名
   * @param value 条件值
   */
  lessThan: (field: string, value: any): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.LESS_THAN, field, value];
  },

  /**
   * 构建小于等于条件
   * @param field 字段名
   * @param value 条件值
   */
  lessThanOrEqual: (field: string, value: any): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.LESS_THAN_OR_EQUAL, field, value];
  },

  /**
   * 构建LIKE条件（添加%value%通配符实现包含匹配）
   * @param field 字段名
   * @param value 条件值
   */
  like: (field: string, value: string): any[] => {
    if (value === undefined || value === null || value === '') return [];

    // 检查是否已经包含通配符
    if (value.startsWith('%') && value.endsWith('%')) {
      // 已经有前后通配符，保持原样
      return [QueryOperator.LIKE, field, value];
    } else {
      // 添加通配符
      return [QueryOperator.LIKE, field, `%${value}%`];
    }
  },

  /**
   * 构建开头匹配条件（添加value%通配符）
   * @param field 字段名
   * @param value 条件值
   */
  startsWith: (field: string, value: string): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.LIKE, field, `${value}%`];
  },

  /**
   * 构建结尾匹配条件（添加%value通配符）
   * @param field 字段名
   * @param value 条件值
   */
  endsWith: (field: string, value: string): any[] => {
    if (value === undefined || value === null || value === '') return [];
    return [QueryOperator.LIKE, field, `%${value}`];
  },

  /**
   * 构建IN条件
   * @param field 字段名
   * @param values 条件值数组
   */
  in: (field: string, values: any[]): any[] => {
    if (!Array.isArray(values) || values.length === 0) return [];
    return [QueryOperator.IN, field, values];
  },

  /**
   * 构建NOT IN条件
   * @param field 字段名
   * @param values 条件值数组
   */
  notIn: (field: string, values: any[]): any[] => {
    if (!Array.isArray(values) || values.length === 0) return [];
    return [QueryOperator.NOT_IN, field, values];
  },

  /**
   * 构建BETWEEN条件
   * @param field 字段名
   * @param start 开始值
   * @param end 结束值
   */
  between: (field: string, start: any, end: any): any[] => {
    if (start === undefined || start === null || end === undefined || end === null) return [];
    return [QueryOperator.BETWEEN, field, [start, end]];
  },

  /**
   * 构建范围条件 (min <= field <= max)
   * @param field 字段名
   * @param min 最小值
   * @param max 最大值
   */
  range: (field: string, min?: any, max?: any): any[] => {
    const conditions: any[] = [];

    if (min !== undefined && min !== null) {
      conditions.push([QueryOperator.GREATER_THAN_OR_EQUAL, field, min]);
    }

    if (max !== undefined && max !== null) {
      conditions.push([QueryOperator.LESS_THAN_OR_EQUAL, field, max]);
    }

    if (conditions.length === 0) {
      return [];
    }

    if (conditions.length === 1) {
      return conditions[0];
    }

    return [QueryOperator.AND, ...conditions];
  },

  /**
   * 构建AND条件组
   * @param conditions 子条件数组
   */
  and: (...conditions: any[]): any[] => {
    const validConditions = conditions.filter((c) => Array.isArray(c) && c.length > 0);

    if (validConditions.length === 0) return [];
    if (validConditions.length === 1) return validConditions[0];

    return [QueryOperator.AND, ...validConditions];
  },

  /**
   * 构建OR条件组
   * @param conditions 子条件数组
   */
  or: (...conditions: any[]): any[] => {
    const validConditions = conditions.filter((c) => Array.isArray(c) && c.length > 0);

    if (validConditions.length === 0) return [];
    if (validConditions.length === 1) return validConditions[0];

    return [QueryOperator.OR, ...validConditions];
  },

  /**
   * 构建对象形式的查询条件
   * 简化的MongoDB风格语法
   * @param obj 对象形式的查询条件
   */
  object: (obj: Record<string, any>): any => {
    // 创建一个新的对象，不修改原始对象
    const result: Record<string, any> = {};

    // 过滤掉空值
    for (const key in obj) {
      const value = obj[key];

      // 如果值是对象但不是数组，检查是否有操作符
      if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
        const opObj: Record<string, any> = {};
        let hasValidOp = false;

        for (const op in value) {
          const opValue = value[op];

          // 跳过空值
          if (
            opValue === undefined ||
            opValue === null ||
            (Array.isArray(opValue) && opValue.length === 0) ||
            opValue === ''
          ) {
            continue;
          }

          opObj[op] = opValue;
          hasValidOp = true;
        }

        if (hasValidOp) {
          result[key] = opObj;
        }
      }
      // 如果是数组，检查是否为空
      else if (Array.isArray(value)) {
        if (value.length > 0) {
          result[key] = value;
        }
      }
      // 其他非空值直接添加
      else if (value !== undefined && value !== null && value !== '') {
        result[key] = value;
      }
    }

    return result;
  },

  /**
   * 创建一个映射函数，将对象属性映射为条件
   * @param mapper 映射函数
   */
  map: <T extends object>(obj: T, mapper: (key: keyof T, value: any) => any[]): any[] => {
    const conditions: any[][] = [];

    for (const key in obj) {
      const value = obj[key];

      // 跳过空值
      if (
        value === undefined ||
        value === null ||
        value === '' ||
        (Array.isArray(value) && value.length === 0)
      ) {
        continue;
      }

      const condition = mapper(key as keyof T, value);
      if (Array.isArray(condition) && condition.length > 0) {
        conditions.push(condition);
      }
    }

    if (conditions.length === 0) {
      return [];
    }

    if (conditions.length === 1) {
      return conditions[0];
    }

    return [QueryOperator.AND, ...conditions];
  },

  /**
   * 智能构建查询条件
   * 根据字段值类型自动生成适当的查询条件
   * @param obj 包含查询条件的对象
   * @param options 配置选项
   * @returns 查询条件数组
   */
  smartQuery: <T extends Record<string, any>>(
    obj: T,
    options: {
      /** 指定字段使用的操作符 */
      fieldOperators?: Record<
        string,
        {
          /** 指定操作符 */
          operator?: string;
          /** 自定义处理函数 */
          handler?: (field: string, value: any) => any[];
          /** 前缀 */
          prefix?: string;
          /** 后缀 */
          suffix?: string;
        }
      >;
      /** 仅包含这些字段 */
      include?: string[];
      /** 排除这些字段 */
      exclude?: string[];
      /** 是否字符串自动使用模糊匹配 */
      autoLike?: boolean;
      /** 自定义数组处理方式 */
      arrayMode?: 'in' | 'range' | 'auto';
      /** 字符串值是否区分大小写 */
      caseSensitive?: boolean;
      /** 分组配置 */
      groups?: {
        /** 指定字段列表使用AND分组 */
        and?: string[][];
        /** 指定字段列表使用OR分组 */
        or?: string[][];
      };
    } = {},
  ): any[] => {
    // 默认选项
    const defaultOptions = {
      autoLike: true,
      arrayMode: 'auto',
      caseSensitive: true,
    };

    // 合并选项
    const finalOptions = { ...defaultOptions, ...options };

    // 存储所有条件
    const conditions: any[] = [];

    // 用于标记处理过的字段
    const processedFields = new Set<string>();

    // 处理分组
    if (finalOptions.groups) {
      // 处理AND分组
      if (finalOptions.groups.and) {
        for (const fieldGroup of finalOptions.groups.and) {
          const groupConditions: any[] = [];

          for (const field of fieldGroup) {
            if (field in obj && !processedFields.has(field)) {
              const value = obj[field];
              if (QueryTools.isValidValue(value)) {
                const condition = QueryTools.smartProcessField(field, value, finalOptions);
                if (condition.length > 0) {
                  groupConditions.push(condition);
                  processedFields.add(field);
                }
              }
            }
          }

          if (groupConditions.length > 0) {
            if (groupConditions.length === 1) {
              conditions.push(groupConditions[0]);
            } else {
              conditions.push([QueryOperator.AND, ...groupConditions]);
            }
          }
        }
      }

      // 处理OR分组
      if (finalOptions.groups.or) {
        for (const fieldGroup of finalOptions.groups.or) {
          const groupConditions: any[] = [];

          for (const field of fieldGroup) {
            if (field in obj && !processedFields.has(field)) {
              const value = obj[field];
              if (QueryTools.isValidValue(value)) {
                const condition = QueryTools.smartProcessField(field, value, finalOptions);
                if (condition.length > 0) {
                  groupConditions.push(condition);
                  processedFields.add(field);
                }
              }
            }
          }

          if (groupConditions.length > 0) {
            if (groupConditions.length === 1) {
              conditions.push(groupConditions[0]);
            } else {
              conditions.push([QueryOperator.OR, ...groupConditions]);
            }
          }
        }
      }
    }

    // 处理剩余字段
    for (const field in obj) {
      // 跳过已处理的字段
      if (processedFields.has(field)) continue;

      // 根据include和exclude配置过滤字段
      if (finalOptions.include && !finalOptions.include.includes(field)) continue;
      if (finalOptions.exclude && finalOptions.exclude.includes(field)) continue;

      const value = obj[field];

      // 跳过无效值
      if (!QueryTools.isValidValue(value)) continue;

      // 处理特殊的嵌套分组
      if (field === '$and' && Array.isArray(value)) {
        const andConditions = value
          .filter((item: any) => item && typeof item === 'object')
          .map((item: any) => QueryTools.smartQuery(item, finalOptions as any))
          .filter((condition: any[]) => condition.length > 0);

        if (andConditions.length > 0) {
          if (andConditions.length === 1) {
            conditions.push(andConditions[0]);
          } else {
            conditions.push([QueryOperator.AND, ...andConditions]);
          }
        }
        continue;
      }

      if (field === '$or' && Array.isArray(value)) {
        const orConditions = value
          .filter((item: any) => item && typeof item === 'object')
          .map((item: any) => QueryTools.smartQuery(item, finalOptions as any))
          .filter((condition: any[]) => condition.length > 0);

        if (orConditions.length > 0) {
          if (orConditions.length === 1) {
            conditions.push(orConditions[0]);
          } else {
            conditions.push([QueryOperator.OR, ...orConditions]);
          }
        }
        continue;
      }

      // 处理普通字段
      const condition = QueryTools.smartProcessField(field, value, finalOptions);
      if (condition.length > 0) {
        conditions.push(condition);
      }
    }

    // 返回最终条件
    if (conditions.length === 0) {
      return [];
    } else if (conditions.length === 1) {
      return conditions[0];
    } else {
      return [QueryOperator.AND, ...conditions];
    }
  },

  /**
   * 智能处理单个字段
   * @private
   */
  smartProcessField: (field: string, value: any, options: any): any[] => {
    // 检查是否有自定义处理
    if (options.fieldOperators && options.fieldOperators[field]) {
      const fieldOp = options.fieldOperators[field];

      // 使用自定义处理函数
      if (fieldOp.handler && typeof fieldOp.handler === 'function') {
        return fieldOp.handler(field, value);
      }

      // 使用指定操作符
      if (fieldOp.operator) {
        // 添加前缀和后缀
        let finalValue = value;
        if (typeof value === 'string') {
          if (fieldOp.prefix) finalValue = fieldOp.prefix + finalValue;
          if (fieldOp.suffix) finalValue = finalValue + fieldOp.suffix;
        }

        return [fieldOp.operator, field, finalValue];
      }
    }

    // 根据值类型自动处理

    // 1. 数组处理
    if (Array.isArray(value)) {
      // 空数组跳过
      if (value.length === 0) return [];

      // 过滤数组中的无效值
      const validValues = value.filter(
        (item) => item !== undefined && item !== null && item !== '',
      );

      // 如果过滤后数组为空，则跳过
      if (validValues.length === 0) return [];

      // 如果过滤后只有一个元素，考虑使用等于条件
      if (validValues.length === 1) {
        const value = validValues[0];

        // 如果是日期字符串，尝试转换为日期对象
        if (typeof value === 'string') {
          const date = new Date(value);
          if (!isNaN(date.getTime())) {
            // 是有效的日期字符串，使用等于条件
            return QueryTools.equal(field, date);
          }
        }

        // 其他情况使用普通等于条件
        return QueryTools.equal(field, value);
      }

      // 含有两个元素的数组
      if (validValues.length === 2) {
        const [first, second] = validValues;

        // 方式由arrayMode决定
        if (options.arrayMode === 'in') {
          // 强制使用IN
          return QueryTools.in(field, validValues);
        } else if (options.arrayMode === 'range') {
          // 强制使用范围
          return QueryTools.range(field, first, second);
        } else if (options.arrayMode === 'auto') {
          // 自动判断

          // 如果两个值都是数字，且第一个小于第二个，认为是范围
          if (typeof first === 'number' && typeof second === 'number' && first <= second) {
            return QueryTools.range(field, first, second);
          }

          // 如果是日期对象
          if (first instanceof Date && second instanceof Date) {
            if (first <= second) {
              return QueryTools.between(field, first, second);
            }
          }

          // 如果两个值都是日期字符串，认为是日期范围
          if (typeof first === 'string' && typeof second === 'string') {
            const firstDate = new Date(first);
            const secondDate = new Date(second);

            if (!isNaN(firstDate.getTime()) && !isNaN(secondDate.getTime())) {
              // 确保范围有效（开始不晚于结束）
              if (firstDate <= secondDate) {
                return QueryTools.between(field, firstDate, secondDate);
              } else {
                // 如果日期范围颠倒了，自动调整顺序
                return QueryTools.between(field, secondDate, firstDate);
              }
            }
          }

          // 默认使用IN
          return QueryTools.in(field, validValues);
        }
      }

      // 有三个或更多元素的数组
      if (validValues.length > 2) {
        // 检查是否所有元素都是日期格式
        const allDates = validValues.every((value) => {
          if (value instanceof Date) return true;
          if (typeof value === 'string') {
            const date = new Date(value);
            return !isNaN(date.getTime());
          }
          return false;
        });

        if (allDates) {
          // 如果都是日期，转换为日期对象数组
          const dateValues = validValues.map((value) => {
            if (value instanceof Date) return value;
            return new Date(value as string);
          });

          // 数组中都是日期，使用IN条件
          return QueryTools.in(field, dateValues);
        }
      }

      // 默认使用IN
      return QueryTools.in(field, validValues);
    }

    // 2. 字符串处理
    if (typeof value === 'string') {
      // 如果启用自动模糊匹配
      if (options.autoLike) {
        // 所有字符串都使用模糊匹配，不管是否包含 %
        return QueryTools.like(field, value);
      }

      // 默认使用等于
      return QueryTools.equal(field, value);
    }

    // 3. 布尔值处理
    if (typeof value === 'boolean') {
      return QueryTools.equal(field, value);
    }

    // 4. 数值处理
    if (typeof value === 'number') {
      return QueryTools.equal(field, value);
    }

    // 5. 日期处理
    if (value instanceof Date) {
      return QueryTools.equal(field, value);
    }

    // 6. 对象处理 - 认为是MongoDB风格查询
    if (typeof value === 'object' && value !== null) {
      // 处理操作符
      for (const op in value) {
        const opValue = value[op];
        if (!QueryTools.isValidValue(opValue)) continue;

        switch (op) {
          case '$eq':
            return QueryTools.equal(field, opValue);
          case '$ne':
            return QueryTools.notEqual(field, opValue);
          case '$gt':
            return QueryTools.greaterThan(field, opValue);
          case '$gte':
            return QueryTools.greaterThanOrEqual(field, opValue);
          case '$lt':
            return QueryTools.lessThan(field, opValue);
          case '$lte':
            return QueryTools.lessThanOrEqual(field, opValue);
          case '$like':
            // 检查是否已经包含通配符
            if (typeof opValue === 'string' && opValue.startsWith('%') && opValue.endsWith('%')) {
              // 已经有前后通配符，保持原样
              return [QueryOperator.LIKE, field, opValue];
            } else {
              // 添加通配符
              return [QueryOperator.LIKE, field, `%${opValue}%`];
            }
          case '$startsWith':
            return QueryTools.startsWith(field, opValue);
          case '$endsWith':
            return QueryTools.endsWith(field, opValue);
          case '$in':
            return Array.isArray(opValue) ? QueryTools.in(field, opValue) : [];
          case '$nin':
            return Array.isArray(opValue) ? QueryTools.notIn(field, opValue) : [];
          case '$between':
            return Array.isArray(opValue) && opValue.length === 2
              ? QueryTools.between(field, opValue[0], opValue[1])
              : [];
        }
      }
    }

    // 默认等于
    return QueryTools.equal(field, value);
  },

  /**
   * 检查值是否有效（非空）
   * @private
   */
  isValidValue: (value: any): boolean => {
    // 空字符串、null、undefined视为无效值
    if (value === undefined || value === null || value === '') {
      return false;
    }

    // 空数组视为无效值
    if (Array.isArray(value) && value.length === 0) {
      return false;
    }

    // 其他值视为有效
    return true;
  },
};
